/**
 * MCP Server Manager
 * 
 * Manages MCP servers (stdio, HTTP/SSE, and SDK MCP servers)
 * Based on: https://docs.claude.com/en/api/agent-sdk/mcp
 */

import type { McpServerConfig } from '@/types';
import { logger } from '@/utils/logger';
import { toolRegistry } from './tool-factory';
import { builtinTools } from './builtin';

/**
 * MCP Server Manager
 * 
 * Handles registration and configuration of MCP servers
 */
export class McpServerManager {
  private servers: Map<string, McpServerConfig> = new Map();
  private sdkServers: Map<string, any> = new Map();

  constructor() {
    // Register built-in tools on initialization
    this.registerBuiltinTools();
  }

  /**
   * Register all built-in tools
   */
  private registerBuiltinTools(): void {
    logger.info('Registering built-in tools');
    toolRegistry.registerTools(builtinTools);
    
    // Create a default SDK MCP server with all built-in tools
    const builtinServer = toolRegistry.createServer(
      'builtin',
      builtinTools.map(t => t.name)
    );
    
    this.sdkServers.set('builtin', builtinServer);
    logger.info('Created built-in SDK MCP server');
  }

  /**
   * Register an external MCP server (stdio or HTTP/SSE)
   */
  registerServer(name: string, config: McpServerConfig): void {
    logger.info(`Registering MCP server: ${name}`, { type: config.type });
    this.servers.set(name, config);
  }

  /**
   * Register an SDK MCP server
   */
  registerSdkServer(name: string, toolNames: string[]): void {
    logger.info(`Registering SDK MCP server: ${name} with ${toolNames.length} tools`);
    
    const server = toolRegistry.createServer(name, toolNames);
    this.sdkServers.set(name, server);
  }

  /**
   * Get server configuration for Claude Agent SDK
   * 
   * Returns a configuration object that can be passed to the `mcpServers` option
   */
  getServerConfig(): Record<string, any> {
    const config: Record<string, any> = {};
    
    // Add SDK MCP servers
    this.sdkServers.forEach((server, name) => {
      config[name] = {
        type: 'sdk',
        instance: server,
      };
    });
    
    // Add external MCP servers
    this.servers.forEach((serverConfig, name) => {
      if (serverConfig.type === 'stdio') {
        config[name] = {
          command: serverConfig.command,
          args: serverConfig.args || [],
          env: serverConfig.env || {},
        };
      } else if (serverConfig.type === 'sse' || serverConfig.type === 'http') {
        config[name] = {
          url: serverConfig.url,
          headers: serverConfig.headers || {},
        };
      }
    });
    
    return config;
  }

  /**
   * Get all registered server names
   */
  getServerNames(): string[] {
    const sdkNames = Array.from(this.sdkServers.keys());
    const externalNames = Array.from(this.servers.keys());
    return [...sdkNames, ...externalNames];
  }

  /**
   * Get server by name
   */
  getServer(name: string): McpServerConfig | any | undefined {
    return this.sdkServers.get(name) || this.servers.get(name);
  }

  /**
   * Remove a server
   */
  removeServer(name: string): boolean {
    const removedSdk = this.sdkServers.delete(name);
    const removedExternal = this.servers.delete(name);
    
    if (removedSdk || removedExternal) {
      logger.info(`Removed MCP server: ${name}`);
      return true;
    }
    
    return false;
  }

  /**
   * Get all available tools from all servers
   */
  getAllAvailableTools(): string[] {
    const tools = new Set<string>();
    
    // Add tools from SDK servers
    this.sdkServers.forEach((server, name) => {
      const serverTools = toolRegistry.getAllTools()
        .filter(tool => {
          // Check if this tool belongs to this server
          // Tool names in SDK MCP servers are prefixed with mcp__{server_name}__{tool_name}
          return true; // For now, include all tools
        })
        .map(tool => `mcp__${name}__${tool.name}`);
      
      serverTools.forEach(tool => tools.add(tool));
    });
    
    return Array.from(tools);
  }

  /**
   * Load MCP server configuration from .mcp.json file
   */
  async loadFromConfig(configPath: string): Promise<void> {
    try {
      const { readFile } = await import('fs/promises');
      const configContent = await readFile(configPath, 'utf-8');
      const config = JSON.parse(configContent);
      
      if (config.mcpServers) {
        Object.entries(config.mcpServers).forEach(([name, serverConfig]: [string, any]) => {
          this.registerServer(name, serverConfig);
        });
        
        logger.info(`Loaded ${Object.keys(config.mcpServers).length} MCP servers from config`);
      }
    } catch (error) {
      logger.warn(`Failed to load MCP config from ${configPath}`, error);
    }
  }
}

/**
 * Global MCP server manager instance
 */
export const mcpManager = new McpServerManager();

